package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DevicePropertiesVo;
import com.zzyl.nursing.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;

/**
 * 设备Service业务层处理
 *
 * @author ruoyi
 * @date 2025-09-26
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient iotDAClient;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 查询设备
     *
     * @param id 设备主键
     * @return 设备
     */
    @Override
    public Device selectDeviceById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询设备列表
     *
     * @param device 设备
     * @return 设备
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int insertDevice(Device device)
    {
        return save(device) ? 1 : 0;
    }

    /**
     * 修改设备
     *
     * @param device 设备
     * @return 结果
     */
    @Override
    public int updateDevice(Device device)
    {
        return updateById(device) ? 1 : 0;
    }

    /**
     * 批量删除设备
     *
     * @param ids 需要删除的设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除设备信息
     *
     * @param id 设备主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id)
    {
        return removeById(id) ? 1 : 0;
    }

    @Override
    public void syncProductList() {
        ListProductsResponse listProductsResponse = iotDAClient.listProducts(new ListProductsRequest());
        if(listProductsResponse.getHttpStatusCode()==200){
            List<ProductSummary> products = listProductsResponse.getProducts();
            redisTemplate.opsForValue().set("iot:all_products", JSONUtil.toJsonStr(products));
        }
    }

    @Override
    public List<ProductVo> allProduct() {
        String s = redisTemplate.opsForValue().get("iot:all_products");
        List<ProductVo> list = JSONUtil.toList(s, ProductVo.class);
        return list;
    }

    @Override
    public void register(DeviceDto deviceDto) {
        //查询设备名称是否重复
        QueryWrapper<Device> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_name",deviceDto.getDeviceName());
        Long count = deviceMapper.selectCount(queryWrapper);
        if(count >0 ){
           throw new RuntimeException("该设备已存在");
        }
        //查询设备标识是否重复
        QueryWrapper<Device> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("node_id",deviceDto.getNodeId());
        Long count2 = deviceMapper.selectCount(queryWrapper2);
        if(count2 >0 ){
            throw new RuntimeException("该设备已存在");
        }
        //查询同一位置是否绑定同一个设备
        QueryWrapper<Device> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("location_type",deviceDto.getLocationType());
        queryWrapper3.eq("physical_location_type",deviceDto.getPhysicalLocationType());
        queryWrapper3.eq("binding_location",deviceDto.getBindingLocation());
        queryWrapper3.eq("product_key",deviceDto.getProductKey());
        Long count3 = deviceMapper.selectCount(queryWrapper3);
        if(count3 >0 ){
            throw new RuntimeException("该位置已有相同设备的产品");
        }
        //注册设备到iot
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        body.withProductId(deviceDto.getProductKey());
        //body.withDeviceId();iot 会自动生成
        body.withDeviceName(deviceDto.getDeviceName());
        body.withNodeId(deviceDto.getNodeId());
        body.withDescription(deviceDto.getDeviceDescription());

        AuthInfo authInfo = new AuthInfo();
        authInfo.withAuthType("SECRET")
                        .withSecret(UUID.randomUUID().toString().replaceAll("-",""))
                        .withSecureAccess(true);
        body.withAuthInfo(authInfo);


        request.withBody(body);
        AddDeviceResponse addDeviceResponse = iotDAClient.addDevice(request);
        if(addDeviceResponse.getHttpStatusCode()==201){
           //插入到数据库
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            device.setIotId(addDeviceResponse.getDeviceId());
            device.setSecret(request.getBody().getAuthInfo().getSecret());
            device.setHaveEntranceGuard(0);
            deviceMapper.insert(device);
        }
    }

    @Override
    public DeviceDetailVo iotDetail(String iotId) {
        DeviceDetailVo deviceDetailVo = new DeviceDetailVo();
        Device device = deviceMapper.selectOne(new QueryWrapper<Device>().eq("iot_id", iotId));
        BeanUtil.copyProperties(device,deviceDetailVo);

        ShowDeviceRequest request = new ShowDeviceRequest();
        request.withDeviceId(iotId);
        ShowDeviceResponse showDeviceResponse = iotDAClient.showDevice(request);
        deviceDetailVo.setDeviceStatus(showDeviceResponse.getStatus());

        LocalDateTime eventTime =  LocalDateTimeUtil.parse(showDeviceResponse.getActiveTime(), "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        //日期时区转换
        LocalDateTime alarmTime = eventTime.atZone(ZoneId.from(ZoneOffset.UTC))
                .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();

        deviceDetailVo.setActiveTime(alarmTime);

        return deviceDetailVo;
    }

    @Override
    public List<DevicePropertiesVo> queryServiceProperties(String iotId) {

        ShowDeviceShadowResponse showDeviceShadowResponse = iotDAClient.showDeviceShadow(new ShowDeviceShadowRequest().withDeviceId(iotId));
        if(showDeviceShadowResponse.getHttpStatusCode()!=200){
            throw new RuntimeException("查询设备属性失败");
        }
        List<DeviceShadowData> shadow = showDeviceShadowResponse.getShadow();

        List<DevicePropertiesVo> list = new ArrayList<>();
        shadow.forEach(deviceShadowData -> {
            Object properties = deviceShadowData.getReported().getProperties();
            Map<String,Object> map = (Map<String, Object>) properties;
            map.forEach((key,value)->{
                DevicePropertiesVo devicePropertiesVo = new DevicePropertiesVo();
                devicePropertiesVo.setFunctionId(key);
                devicePropertiesVo.setValue(value.toString());

                 //处理上报时间日期
                LocalDateTime eventTime =  LocalDateTimeUtil.parse(deviceShadowData.getReported().getEventTime(), "yyyyMMdd'T'HHmmss'Z'");
                //日期时区转换
                LocalDateTime alarmTime = eventTime.atZone(ZoneId.from(ZoneOffset.UTC))
                        .withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                        .toLocalDateTime();
                devicePropertiesVo.setEventTime(alarmTime);
                list.add(devicePropertiesVo);

            });

           });

        return list;
    }

    @Override
    public List<ServiceCapability> queryProduct(String productKey) {
        ShowProductRequest request = new ShowProductRequest();
        request.setProductId(productKey);
        ShowProductResponse showProductResponse = iotDAClient.showProduct(request);
        if(showProductResponse.getHttpStatusCode()!=200){
            throw new RuntimeException("产品信息不存在");
        }
        List<ServiceCapability> serviceCapabilities = showProductResponse.getServiceCapabilities();
        return serviceCapabilities;

    }
}
